#ifndef __PROCEE__POOL__HPP
#define __PROCEE__POOL__HPP

#include<sys/types.h>
#include<cstdlib>
#include<iostream>
#include<unistd.h>
#include<string>
#include<vector>
#include<functional>

using func_t =std::function<void (int fd)>;
//等价于 typedef std:: std::function<void (int fd)> func_t;定义了一个函数类型

const int process_num =5;

#endif 


// 先描述 ，，在组织
class Channel // 描述信道，存进程信息
{
public:
    Channel() {}
    Channel(int fd, const std::string &name, pid_t id)
        : _wfd(fd),
          _name(name),
          _sub_target(id)
    {
    }
    void DebugPrint()
    {
        printf("channel name :%s, wfd: %d,target pid:%d\n", _name.c_str(), _wfd, _sub_target);
    }
    ~Channel() {}

    int Fd() { return _wfd; }
    std::string Name() { return _name; }
    pid_t Target() { return _sub_target; }

private:
    int _wfd; // 写文件描述符
    std::string _name;
    pid_t _sub_target; // 目标子进程是谁

    // int load;//负载
};

// 父进程
class ProcessPool
{
public:
    ProcessPool(int num = process_num) : _processnum(num)
    {
    }
    ~ProcessPool() {}

    bool InitProcessPool(callback_t cb) // 初始化进程池
    {
        for (int i = 0; i < process_num; i++) // 未来走for循环的只能是父进程，子进程根本走不到for循环
        {
            // 1.创建管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return false;

            // 2.创建子进程
            pid_t id = fork();
            if (id < 0)
                return false;
            if (id == 0)
            {
                // 3.关闭不需要的读或写端 ，形成信道
                // 父写子读
                close(pipefd[1]);
                // 子进程将来在这里做事情
                // 子进程该干什么？
                cb(pipefd[0]); // 子进程执行回调方法

                exit(0);
            }

            close(pipefd[0]);
            std::string name = "channel-" + std::to_string(i);
            channels.emplace_back(pipefd[1], name, id); // 构造并在容器末尾插入新元素
            sleep(1);
        }
    };
    // 在组织
    std::vector<Channel> channels; // 表示未来的所有信道

    // 1.创建进程池，让子进程进入自己的工作流中，父进程得到channels
    InitProcessPool(channels, [](int fd)
                    {
    while(true)
    {
        int code=0;
        std::cout<<"子进程阻塞："<< getpid()<< std::endl;
        ssize_t n=read(fd,&code,sizeof(code)); //子进程卡在这里等父进程发送消息
        if(n>0) //说明读取成功
        {
            std::cout<< "子进程被唤醒 :"<< getpid()<<std::endl;
        }
    } });

    // 2.控制唤醒指定的一个子进程，让该子进程完成指定任务
    // 父进程要均衡的选择信道--->轮询或者随机数或load计数 --负载均衡

    void CtrlProcess()
    {
        int index = 0;
        while (true)
        {
            int who = index;
            index++;
            index %= channels.size();

            int x = 1;
            std::cout << "选择信道" << channels[who].Name() << ", subtaret:" << channels[who].Target() << std::endl;
            write(channels[who].Fd(), &x, sizeof(x));
            sleep(1);
        }
    }

    // for (auto c : channels)
    // {
    //     c.DebugPrint();
    // }
    // sleep(10);

    // 父进程，父进程对子进程的控制，就会转换成为对channels的使用

private:
    std::vector<Channel> channels; // 所有信道
    int _processnum;               // 有多少进程
}
